perm filename NF.SAI[4,KMC] blob
sn#180017 filedate 1975-10-04 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00013 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 BEGIN
C00004 00003 α INIT_TABLE INIT_TABLES
C00007 00004 α LEARN DUMP_DATA
C00010 00005 α LOOK_UP LOOK_UP_xxxxxx
C00013 00006 α OPEN_DISK INITIALIZE
C00015 00007 α SUBSET RESULT
C00017 00008 α FIND_WORD
C00022 00009 α VOCABULARY
C00023 00010 α FIND_WORDS ANAPH_REF
C00026 00011 α CANONIZE
C00029 00012 α MATCH1 MATCH
C00032 00013 α This selects the requested routine
C00033 ENDMK
C⊗;
BEGIN
REQUIRE "IODEFS.SAI[SEC,RCP]" SOURCE_FILE;
SAFE STRING ARRAY CLEAN, NEAR[0:127];
PROC INIT_CHAR(VALUE STRING SPECIAL, NEARBY);
BEGIN
STRING GROUP, VAL;
INTEGER CHAR;
α Establish the character conversions;
FOR I ← 0 TIL 127 DO CLEAN[I] ← " ";
FOR I ← "0" TIL "9" DO CLEAN[I] ← I;
FOR I ← "A" TIL "Z" DO CLEAN[I] ← I;
FOR I ← "a" TIL "z" DO CLEAN[I] ← I - 32;
WHILE (GROUP ← SCAN(SPECIAL, 2, BRK)) DO
BEGIN
VAL ← GROUP[1 TO 1];
WHILE (CHAR ← LOP(GROUP)) DO CLEAN[CHAR] ← VAL;
END;
α Establish character "nearness";
FOR I ← 0 TIL 127 DO NEAR[I] ← NULL;
WHILE (GROUP ← SCAN(NEARBY, 2, BRK)) DO
BEGIN
VAL ← LOP(GROUP);
WHILE (CHAR ← LOP(GROUP)) DO NEAR[CHAR] ← NEAR[CHAR] & VAL;
END;
END;
STRING PROC CLEAN_UP;
BEGIN
INTEGER CHAR;
STRING LINE, CLEANED;
LINE ← IF FILE THEN IN_LINE ELSE GET_A_STRING("Type garbage:");
CLEANED ← NULL;
WHILE (CHAR ← LOP(LINE)) DO CLEANED ← CLEANED & CLEAN[CHAR];
OUT_LINE(CLEANED);
RETURN(CLEANED);
END;
BOOLEAN PROC MEM(VALUE STRING WORD, S1, S2, S3);
RETURN(EQU((WORD ← WORD[1 TO 3]), S1) OR EQU(WORD, S2) OR EQU(WORD, S3));
α INIT_TABLE INIT_TABLES;
SAFE INTEGER ARRAY BOUNDS[1:8];
DEFINE USE_PREFIX="1", USE_SUFFIX="3", USE_DICTIO="5", USE_MULTI="7";
INTEGER AFFIX_LEN;
PROC INIT_TABLE(VALUE STRING FNAME; REFERENCE STRING ARRAY TABLE, ON, MAKES;
VALUE INTEGER USE_TABLE);
BEGIN
STRING LINE;
INTEGER SIZE;
FILIN(FNAME & "[PAR,RCP]", INCH2);
EAT_DIR(INCH2);
SIZE ← 0;
WHILE (LINE ← INPUT(INCH2, 1)) AND (SIZE ← SIZE+1) ≤ BOUNDS[USE_TABLE+1] DO
BEGIN
TABLE[SIZE] ← SCAN(LINE, 3, BRK);
IF MEM(FNAME,"PRE","SUF",NULL) THEN ON[SIZE] ← (SCAN(LINE, 3, BRK));
MAKES[SIZE] ← SCAN(LINE, 4, BRK);
END;
IF SIZE > BOUNDS[USE_TABLE+1] THEN
BEGIN
OUTSTR(FNAME ∂ "table full" ↓);
SIZE ← SIZE - 1;
END;
BOUNDS[USE_TABLE] ← SIZE;
RELEASE(INCH2);
END;
SAFE STRING ARRAY PREFIX, P_ON, P_MAKES[1:15];
SAFE STRING ARRAY SUFFIX, S_ON, S_MAKES[1:60];
SAFE STRING ARRAY DICTIO, MEANS[1:2000];
SAFE STRING ARRAY MULTI, SIMP[1:50];
PROC INIT_TABLES;
BEGIN
AFFIX_LEN ← 5;
α Read the table of prefixes;
BOUNDS[USE_PREFIX+1] ← 15;
INIT_TABLE("PREFIX", PREFIX, P_ON, P_MAKES, USE_PREFIX);
α Read the table of suffixes;
BOUNDS[USE_SUFFIX+1] ← 60;
INIT_TABLE("SUFFIX", SUFFIX, S_ON, S_MAKES, USE_SUFFIX);
α Read the dictionary;
BOUNDS[USE_DICTIO+1] ← 2000;
INIT_TABLE("DICTIO", DICTIO, MEANS, MEANS, USE_DICTIO);
α Read the multi-word entries;
BOUNDS[USE_MULTI+1] ← 50;
INIT_TABLE("MULTI", MULTI, SIMP, SIMP, USE_MULTI);
END;
α LEARN DUMP_DATA;
STRING PROC LEARN(VALUE STRING WORD);
BEGIN
STRING MEANING;
MEANING ← GET_A_STRING("What is" ∂ WORD ∂ "[<CR> for nothing]");
IF MEANING THEN
BEGIN
INTEGER NEXT;
NEXT ← BOUNDS[USE_DICTIO] +1;
IF NEXT > BOUNDS[USE_DICTIO+1] THEN
OUTSTR("DICTIO table full" ↓)
ELSE BEGIN
BOUNDS[USE_DICTIO] ← NEXT;
WHILE (NEXT ← NEXT-1) > 0 AND
ALPHA(WORD, DICTIO[NEXT]) > 0 DO
BEGIN
DICTIO[NEXT+1] ← DICTIO[NEXT];
MEANS[NEXT+1] ← MEANS[NEXT];
END;
DICTIO[NEXT + 1] ← WORD;
MEANS[NEXT + 1] ← MEANING;
END;
RETURN(WORD);
END
ELSE RETURN(NULL);
END;
PROC DUMP_DATA;
BEGIN
IF GET_A_STRING("NEAR [Y,N]") = "Y" THEN
FOR I ← 0 TIL 127 DO
IF NEAR[I] THEN OUTSTR(I ∂ "might be" ∂ NEAR[I] ↓);
IF GET_A_STRING("PREFIX [Y,N]") = "Y" THEN
FOR I ← 1 TIL BOUNDS[USE_PREFIX] DO
OUTSTR(PREFIX[I] ∂ "-" ∂ P_ON[I] & TAB & "→" ∂ P_MAKES[I] ↓);
IF GET_A_STRING("SUFFIX [Y,N]") = "Y" THEN
FOR I ← 1 TIL BOUNDS[USE_SUFFIX] DO
OUTSTR(S_ON[I] ∂ "-" ∂ SUFFIX[I] & TAB & "→" ∂ S_MAKES[I] ↓);
IF GET_A_STRING("DICTIO [Y,N]") = "Y" THEN
FOR I ← 1 TIL BOUNDS[USE_DICTIO] DO
OUTSTR(DICTIO[I] & TAB & "→" ∂ MEANS[I] ↓);
IF GET_A_STRING("DICTIO.NEW [Y,N]") = "Y" THEN
BEGIN
FILOUT("DICTIO.NEW[PAR,RCP]", OUCH2);
FOR I ← 1 TIL BOUNDS[USE_DICTIO] DO
OUT(OUCH2, DICTIO[I] & TAB & TAB & TAB & MEANS[I] ↓);
RELEASE(OUCH2);
END;
IF GET_A_STRING("MULTI [Y,N]") = "Y" THEN
FOR I ← 1 TIL BOUNDS[USE_MULTI] DO
OUTSTR(MULTI[I] & TAB & "→" ∂ SIMP[I] ↓);
END;
α LOOK_UP LOOK_UP_xxxxxx;
α Returns index of word in TABLE or else -(index of nearest preceding entry);
INTEGER WINDOWS;
INTEGER PROC LOOK_UP(VALUE STRING WORD; REFERENCE STRING ARRAY TABLE;
VALUE INTEGER USE_TABLE);
BEGIN
INTEGER LB, UB;
IF WINDOWS ≥ 10 THEN OUTSTR("Looking for:" ∂ WORD ↓);
LB ← 0;
UB ← BOUNDS[USE_TABLE] + 1;
WHILE UB > LB+1 DO
BEGIN
INTEGER AT, COMP;
AT ← (LB + UB) DIV 2;
IF (COMP ← ALPHA(WORD, TABLE[AT])) = 0 THEN
BEGIN
WHILE AT > 1 AND EQU(WORD, TABLE[AT-1]) DO AT ← AT-1;
RETURN(AT);
END;
IF COMP > 0 THEN UB ← AT ELSE LB ← AT;
END;
RETURN(-LB);
END;
α Returns index of word in PREFIX or else -(index of nearest preceding entry);
INTEGER PROC LOOK_UP_PREFIX(VALUE STRING WORD);
RETURN(LOOK_UP(WORD, PREFIX, USE_PREFIX));
α Returns index of word in SUFFIX or else -(index of nearest preceding entry);
INTEGER PROC LOOK_UP_SUFFIX(VALUE STRING WORD);
RETURN(LOOK_UP(WORD, SUFFIX, USE_SUFFIX));
α Returns index of word in DICTIO or else -(index of nearest preceding entry);
INTEGER PROC LOOK_UP_DICTIO(VALUE STRING WORD);
RETURN(LOOK_UP(WORD, DICTIO, USE_DICTIO));
α Returns index of word in MULTI or else -(index of nearest preceding entry);
INTEGER PROC LOOK_UP_MULTI(VALUE STRING WORD);
RETURN(LOOK_UP(WORD, MULTI, USE_MULTI));
α OPEN_DISK INITIALIZE;
BOOLEAN ROGER;
PROC OPEN_DISK;
BEGIN
RELEASE(INCH1);
RELEASE(OUCH1);
FILE ← GET_A_STRING("Disk input file [<CR> for none]");
IF FILE THEN
BEGIN
FILIN(FILE, INCH1);
FILOUT(SCAN(FILE, 7, BRK) & ".CLN", OUCH1);
FILE ← "Y";
END
ELSE FILOUT("TYPED.CLN", OUCH1);
END;
BOOLEAN LEARNING, RESPELLED;
INTEGER MISSPELLED, GIBBERISH;
PROC INITIALIZE;
BEGIN
ROGER ← TRUE;
BREAK_LINE;
BREAK_BLANK;
BREAK_TAB;
BREAK_EXT;
SETBREAK(10, " ,.?", NULL, "IRN");
OPEN_DISK;
INIT_CHAR("' ,;: .!) ?",
"WQ TY YTUI UY EI IE '7 O0P AS SA DS GH HG NM MN");
INIT_TABLES;
IF ROGER THEN WINDOWS ← 6 ELSE
WINDOWS ← GET_AN_INT("Windows = [0-10]");
IF ROGER THEN LEARNING ← TRUE ELSE
LEARNING ← GET_A_STRING("Learning [Y,N]") = "Y";
RESPELLED ← FALSE;
MISSPELLED ← GIBBERISH ← 0;
END;
α SUBSET RESULT;
BOOLEAN PROC SUBSET(VALUE STRING ROOT, SSET);
BEGIN
STRING WORD;
IF WINDOWS ≥ 8 THEN OUTSTR(ROOT ∂ "⊂" ∂ SSET ↓);
IF EQU(SSET, "word") THEN RETURN(TRUE);
WHILE (WORD ← SCAN(ROOT, 2, BRK)) DO
BEGIN
INTEGER FOUND;
IF LOP(ROOT) = "←" THEN WORD ← SCAN(ROOT, 2, BRK);
IF WORD = "@" THEN WORD ← WORD[2 TO ∞];
IF EQU(WORD, SSET) THEN RETURN(TRUE);
IF EQU(WORD, "word") THEN RETURN (FALSE);
IF (FOUND ← LOOK_UP_DICTIO(WORD)) > 0 THEN ROOT ← MEANS[FOUND]
ELSE DONE;
IF WINDOWS ≥ 8 THEN OUTSTR(ROOT ∂ "⊂" ∂ SSET ↓);
END;
OUTSTR("Can't find" ∂ WORD ∂ "in DICTIO" ↓);
RETURN(FALSE);
END;
α Attaches information gained from affixes to root;
STRING PROC RESULT(VALUE STRING WORD, MAKES);
BEGIN
IF ¬MAKES THEN RETURN(WORD);
IF MAKES = "←" THEN
BEGIN
STRING ROOT, TEMP;
ROOT ← SCAN(WORD, 2, BRK);
IF WORD = "←" THEN TEMP ← SCAN(WORD, 2, BRK);
IF WORD THEN MAKES ← MAKES ∂ WORD;
RETURN(ROOT ∂ MAKES);
END;
RETURN(WORD ∂ MAKES);
END;
α FIND_WORD;
REQUIRE 100 STRING_PDL;
α Should accept predicted value;
α Should catch numbers (before splitting into 2 words);
RECURSIVE STRING PROC FIND_WORD(VALUE STRING WORD);
BEGIN
INTEGER FOUND, SPLIT, LN_WORD;
STRING ROOT;
LN_WORD ← LN(WORD);
α Try to find the word in the dictionary;
IF LOOK_UP_DICTIO(WORD) > 0 THEN RETURN(WORD);
α Try adding an "E" at the end (short cut for the suffixer);
IF LOOK_UP_DICTIO(WORD & "E") > 0 THEN RETURN(WORD & "E");
FOR SPLIT ← 2 MAX (LN_WORD-AFFIX_LEN+1) TIL LN_WORD DO
α Try to split the word into a root and a suffix;
IF (FOUND ← LOOK_UP_SUFFIX(WORD[SPLIT TO ∞])) > 0 AND
((ROOT ← FIND_WORD(WORD[1 TO SPLIT-1])) OR
(ROOT ← FIND_WORD(WORD[1 TO SPLIT-1] & "E"))) THEN
DO
IF SUBSET(ROOT, S_ON[FOUND]) THEN
BEGIN
RESPELLED ← FALSE;
RETURN(RESULT(ROOT, S_MAKES[FOUND]));
END
UNTIL ¬EQU(SUFFIX[FOUND], SUFFIX[(FOUND ← FOUND+1)]);
FOR SPLIT ← LN_WORD MIN (AFFIX_LEN+1) STEP -1 UNTIL 2 DO
α Try to split the word into a prefix and a root;
IF (FOUND ← LOOK_UP_PREFIX(WORD[1 TO SPLIT-1])) > 0 AND
(ROOT ← FIND_WORD(WORD[SPLIT TO ∞])) AND
SUBSET(ROOT, P_ON[FOUND]) THEN
BEGIN
RESPELLED ← FALSE;
RETURN(RESULT(ROOT, P_MAKES[FOUND]));
END;
FOR SPLIT ← LN_WORD STEP -1 UNTIL 1 DO
BEGIN
STRING NEARBY, CHAR;
α Try replacing a letter with a nearby (or similar) letter;
NEARBY ← NEAR[WORD[SPLIT FOR 1]];
WHILE (CHAR ← LOP(NEARBY)) DO
IF LOOK_UP_DICTIO(WORD[1 TO SPLIT-1] & CHAR &
WORD[SPLIT+1 TO ∞]) > 0 THEN
BEGIN
RESPELLED ← TRUE;
RETURN(WORD[1 TO SPLIT-1] & CHAR & WORD[SPLIT+1 TO ∞]);
END;
α Try removing a letter;
IF LOOK_UP_DICTIO(WORD[1 TO SPLIT-1] & WORD[SPLIT+1 TO ∞]) > 0 THEN
BEGIN
RESPELLED ← TRUE;
RETURN(WORD[1 TO SPLIT-1] & WORD[SPLIT+1 TO ∞]);
END;
END;
α Try transposing 2 letters;
FOR SPLIT ← 2 TIL LN_WORD DO
IF LOOK_UP_DICTIO(WORD[1 TO SPLIT-2] & WORD[SPLIT FOR 1] &
WORD[SPLIT-1 FOR 1] & WORD[SPLIT+1 TO ∞]) > 0 THEN
BEGIN
RESPELLED ← TRUE;
RETURN(WORD[1 TO SPLIT-2] & WORD[SPLIT FOR 1] &
WORD[SPLIT-1 FOR 1] & WORD[SPLIT+1 TO ∞]);
END;
α Try to split the word into 2 words;
FOR SPLIT ← 4 TIL LN_WORD-2 DO
BEGIN
IF LOOK_UP_DICTIO(WORD[1 TO SPLIT-1]) > 0 AND
(ROOT ← FIND_WORD(WORD[SPLIT TO ∞])) THEN
BEGIN
RESPELLED ← TRUE;
RETURN(WORD[1 TO SPLIT-1] ∂ ROOT);
END;
IF LOOK_UP_DICTIO(WORD[SPLIT TO ∞]) > 0 AND
(ROOT ← FIND_WORD(WORD[1 TO SPLIT-1])) THEN
BEGIN
RESPELLED ← TRUE;
RETURN(ROOT ∂ WORD[SPLIT TO ∞]);
END;
END;
α Ask for definition if in LEARNING mode;
IF LEARNING THEN RETURN(LEARN(WORD));
α Nothing worked, give up;
RETURN(NULL);
END;
α VOCABULARY;
PROC VOCABULARY;
BEGIN
STRING LINE;
LINE ← CLEAN_UP;
WHILE ¬EOF DO
BEGIN
WHILE LINE DO
BEGIN
STRING WORD, ROOT;
WORD ← SCAN(LINE, 10, BRK);
IF ¬WORD THEN
BEGIN
WORD ← LOP(LINE);
CONTINUE;
END;
ROOT ← FIND_WORD(WORD);
IF ¬EQU(ROOT, WORD) AND
(WORD ← GET_A_STRING(WORD ∂ "=" ∂ ROOT)) THEN
BEGIN
IF WORD = "?" THEN DUMP_DATA
ELSE WORD ← LEARN(WORD);
END;
END;
LINE ← CLEAN_UP;
END;
END;
α FIND_WORDS ANAPH_REF;
α Should return something besides "←name" for gibberish;
STRING PROC FIND_WORDS(VALUE STRING SENT);
BEGIN
STRING FOUND;
FOUND ← NULL;
WHILE SENT DO
BEGIN
STRING WORD, MEANING;
WORD ← SCAN(SENT, 10, BRK);
IF ¬WORD THEN
BEGIN
WORD ← LOP(SENT);
IF WORD = " " THEN CONTINUE;
END;
IF (MEANING ← FIND_WORD(WORD)) THEN
BEGIN
IF RESPELLED THEN
BEGIN
MISSPELLED ← MISSPELLED + 1;
RESPELLED ← FALSE;
END;
END
ELSE BEGIN
MEANING ← WORD ∂ "←name";
GIBBERISH ← GIBBERISH + 1;
END;
FOUND ← FOUND ∂ MEANING;
END;
IF WINDOWS ≥ 6 THEN
BEGIN
OUTSTR("Found:" ∂ FOUND[2 TO ∞] ↓);
OUTSTR("Missp. =" ∂ CVS(MISSPELLED) & TAB &
"Gibber. =" ∂ CVS(GIBBERISH) ↓);
END;
RETURN(FOUND[2 TO ∞]);
END;
α Should handle multiple-word responses (like "YOUR MOTHER");
STRING PROC ANAPH_REF(VALUE STRING WORD, MEANING);
BEGIN
STRING REF;
IF ROGER AND EQU(MEANING, "noun") THEN
BEGIN
IF EQU(WORD, "I") THEN RETURN("ROGER");
IF EQU(WORD, "YOU") THEN RETURN("PARRY");
IF EQU(WORD, "HERE") THEN RETURN("AT STANFORD");
IF EQU(WORD, "THERE") THEN RETURN("IN THE HOSPITAL");
END;
DO REF ← FIND_WORDS(GET_A_STRING("Referent for:" ∂ WORD))
UNTIL SUBSET(REF, MEANING);
RETURN(REF);
END;
α CANONIZE;
STRING MARKERS;
α Should not be dropping articles and adjectives;
α Should separate markers;
α Should type-check slot fillers;
STRING PROC CANONIZE(VALUE STRING SENT, SLOTS);
BEGIN
STRING WORD, MEANING, ANSWER;
ANSWER ← NULL;
WHILE (WORD ← SCAN(SENT, 2, BRK)) DO
BEGIN
IF WORD = "⊂" THEN
BEGIN
ANSWER ← ANSWER ∂ SCAN(SLOTS, 3, BRK);
CONTINUE;
END;
IF WORD = "λ" THEN
BEGIN
ANSWER ← ANSWER ∂ WORD;
CONTINUE;
END;
IF SENT = "←" THEN
BEGIN
MEANING ← SCAN(SENT, 2, BRK);
WORD ← WORD ∂ MEANING;
MEANING ← MEANING[2 TO ∞];
END
ELSE MEANING ← MEANS[LOOK_UP_DICTIO(WORD)];
IF MEM(MEANING, "aux", "int", "nam") OR
MEM(MEANING, "nou", "pre", "ver") THEN
ANSWER ← ANSWER ∂ WORD
ELSE IF MEM(MEANING, "adv", "mod", "mod") OR
MEM(MEANING, "not", "ten", "wha") THEN
MARKERS ← MARKERS ∂ MEANING & "=" & WORD
ELSE IF MEM(MEANING, "adj", "art", NULL) THEN
OUTSTR("Dropping" ∂ MEANING ∂ WORD ↓)
ELSE IF MEANING = "@" THEN
SENT ← ANAPH_REF(WORD, MEANING[2 TO ∞]) ∂ SENT
ELSE IF MEANING = "con" THEN
ANSWER ← ANSWER ∂ MEANING
ELSE SENT ← MEANING ∂ SENT;
END;
IF WINDOWS ≥ 4 THEN OUTSTR("Canonized:" ∂ ANSWER[2 TO ∞] ↓);
RETURN(ANSWER[2 TO ∞]);
END;
α MATCH1 MATCH;
α Should be explicit verbs in patterns.;
α Should type-check slot fillers;
α Should not just drop clauses - save them for future processing;
α Should search backward so that SSORT ordering in MULTI would give
longest-first. (somehow);
STRING PROC MATCH1(VALUE STRING SENT);
BEGIN
STRING WORD, SENT1;
SENT1 ← SENT;
WORD ← SCAN(SENT1, 2, BRK);
IF LOP(SENT1) = "←" THEN WORD ← SCAN(SENT1, 2, BRK);
WHILE ¬EQU(WORD, "word") DO
BEGIN
INTEGER FOUND;
FOUND ← ABS(LOOK_UP_MULTI(WORD)) + 1;
WHILE EQU(WORD, MULTI[FOUND][1 TO LN(WORD)]) DO
BEGIN
STRING FOUND1, SLOTS;
SENT1 ← SENT;
FOUND1 ← MULTI[FOUND];
SLOTS ← NULL;
WHILE TRUE DO
BEGIN
STRING S, F;
IF ¬(F ← SCAN(FOUND1, 2, BRK)) THEN
BEGIN
F ← CANONIZE(SIMP[FOUND], SLOTS[2 TO ∞]);
IF F = "λ" THEN OUTSTR("Dropping clause:" ∂
SCAN(F, 2, BRK) ∂ "with" ∂ SLOTS[2 TO ∞] ↓);
IF F THEN SENT1 ← F ∂ SENT1;
IF WINDOWS ≥ 2 THEN OUTSTR("Matched:" ∂ SENT1 ↓);
RETURN(SENT1);
END;
IF ¬(S ← SCAN(SENT1, 2, BRK)) THEN DONE;
IF SENT1 = "←" THEN S ← S ∂ SCAN(SENT1, 2, BRK);
IF EQU(F, S) THEN CONTINUE;
IF F ≤ "Z" OR ¬SUBSET(S, F) THEN DONE;
SLOTS ← SLOTS & TAB & S;
END;
FOUND ← FOUND + 1;
END;
WORD ← MEANS[LOOK_UP_DICTIO(WORD)];
END;
OUTSTR("Can't find" ∂ SENT ∂ "in MULTI" ↓ &
" so dropping" ∂ SCAN(SENT, 2, BRK) ↓);
RETURN(SENT);
END;
α Should separate markers;
STRING PROC MATCH(VALUE STRING SENT);
BEGIN
MARKERS ← NULL;
SENT ← CANONIZE(SENT, NULL);
WHILE SENT DO SENT ← MATCH1(SENT);
IF WINDOWS ≥ 2 THEN OUTSTR("Markers:" ∂ MARKERS ↓);
RETURN(SENT);
END;
α This selects the requested routine;
WHILE TRUE DO
BEGIN
STRING JOB;
JOB ← GET_A_STRING("Initialize, set Windows, Dump data, Vocabulary,
Find words, Canonize, Match, eXit");
IF JOB = "I" THEN INITIALIZE
ELSE IF JOB = "W" THEN WINDOWS ← GET_AN_INT("Windows = [0-10]")
ELSE IF JOB = "D" THEN DUMP_DATA
ELSE IF JOB = "V" THEN VOCABULARY
ELSE IF JOB = "F" THEN JOB ← FIND_WORDS(CLEAN_UP)
ELSE IF JOB = "C" THEN JOB ← CANONIZE(FIND_WORDS(CLEAN_UP), NULL)
ELSE IF JOB = "M" THEN JOB ← MATCH(FIND_WORDS(CLEAN_UP))
ELSE IF JOB = "X" THEN DONE
ELSE OUTSTR("You blew it" ↓);
END;
END